package com.cloud.common.core.exception;

import com.cloud.common.core.base.ApiResponse;
import com.cloud.common.core.base.ApiResponseEnum;
import com.cloud.common.core.base.enums.ApiBaseEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Path;
import java.util.List;

/**
 * @author: Dream_xun
 * @date: 2020/7/31 18:06
 * @description: 全局异常处理
 */
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    @SuppressWarnings("unchecked")
    @ExceptionHandler({RuntimeException.class, Exception.class})
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public ResponseEntity<ApiResponse> internalExceptionHandler(Exception e) {
        log.error("internalExceptionHandler: stacktrace", e);
        ApiResponse apiResponse = ApiResponse.respond(ApiResponseEnum.INTERNAL_ERROR);
        return new ResponseEntity(apiResponse, HttpStatus.OK);
    }

    @SuppressWarnings("unchecked")
    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public ResponseEntity<ApiResponse> handleBindException(BindException e) {
        StringBuilder message = new StringBuilder();
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        for (FieldError error : fieldErrors) {
            message.append(error.getField()).append(error.getDefaultMessage()).append(",");
        }
        log.error("handleBindException: stacktrace", e);
        message = new StringBuilder(message.substring(0, message.length() - 1));
        ApiResponse apiResponse = ApiResponse.respond(message.toString());
        return new ResponseEntity(apiResponse, HttpStatus.OK);
    }

    //统一处理请求参数校验(普通传参)
    @SuppressWarnings("unchecked")
    @ExceptionHandler({ConstraintViolationException.class})
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public ResponseEntity<ApiResponse> constraintExceptionHandler(ConstraintViolationException e) {
        ConstraintViolation<?> constraintViolation = e.getConstraintViolations().stream().findFirst().orElse(null);
        if (constraintViolation == null) {
            return new ResponseEntity(ApiResponse.respond(ApiResponseEnum.BAD_REQUEST), HttpStatus.OK);
        }
        Path property = constraintViolation.getPropertyPath();
        String msg = null;
        for (Path.Node node : property) {
            msg = node.getName();
        }
        String errorMsg = "[" + msg + "]" + constraintViolation.getMessage();
        return new ResponseEntity(ApiResponse.respond(ApiResponseEnum.BAD_REQUEST, errorMsg), HttpStatus.OK);
    }

    @SuppressWarnings("unchecked")
    @ExceptionHandler({BizException.class})
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public ResponseEntity<ApiResponse> bizExceptionHandler(BizException bizException) {
        ApiBaseEnum apiBaseEnum = bizException.getApiEnum();
        String customMsg = bizException.getCustomMsg();
        log.error("intercept===BusinessException===info=={}", bizException.getMessage());
        if (apiBaseEnum != null && customMsg != null) {
            return new ResponseEntity(ApiResponse.respond(apiBaseEnum, customMsg), HttpStatus.OK);
        }
        if (customMsg != null) {
            return new ResponseEntity(ApiResponse.respond(customMsg), HttpStatus.OK);
        }
        if (apiBaseEnum != null) {
            return new ResponseEntity(ApiResponse.respond(apiBaseEnum), HttpStatus.OK);
        }
        return new ResponseEntity(ApiResponse.respond(ApiResponseEnum.INTERNAL_ERROR), HttpStatus.OK);
    }
}